package com.csis.framework.db;

import java.io.Serializable;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("baseDao")
@Transactional
public class BaseDao {
	protected Log log = LogFactory.getLog(BaseDao.class);

	@Resource
	private SessionFactory sessionFactory;

	@Transactional(propagation = Propagation.SUPPORTS)
	public void persist(Object o) {
		if (log.isDebugEnabled())
			log.debug("[BaseDao]>Persist>>Transaction>>Status>>"
					+ sessionFactory.getCurrentSession().getTransaction().isActive());
		sessionFactory.getCurrentSession().persist(o);
	}

	@Transactional(propagation = Propagation.SUPPORTS)
	public void merge(Object o) {
		if (log.isDebugEnabled())
			log.debug("[BaseDao]>merge>>Transaction>>Status>>"
					+ sessionFactory.getCurrentSession().getTransaction().isActive());
		sessionFactory.getCurrentSession().merge(o);
	}

	@Transactional(propagation = Propagation.SUPPORTS)
	public <T> void remove(Class<T> clazz, Serializable id) {
		if (log.isDebugEnabled())
			log.debug("[BaseDao]>remove>>Transaction>>Status>>"
					+ sessionFactory.getCurrentSession().getTransaction().isActive());
		sessionFactory.getCurrentSession().delete(load(clazz, id));
	}

	@Transactional(propagation = Propagation.SUPPORTS)
	public void execute(String sql, Object... vals) {
		SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(sql);

		int index = 0;
		if (vals != null && vals.length > 0)
			for (Object val : vals)
				query.setParameter(index++, val);
		query.executeUpdate();

	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public <T> T load(Class<T> clazz, Serializable id) {
		if (log.isDebugEnabled())
			log.debug("[BaseDao]>load>>Transaction>>Status>>"
					+ sessionFactory.getCurrentSession().getTransaction().isActive());
		return ((T) sessionFactory.getCurrentSession().get(clazz, id));
	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public <T> List<T> query4SingleTable(Class<T> clazz, String sql, Object... vals) {
		if (log.isDebugEnabled())
			log.debug("[BaseDao]>query4SingleTable>>Transaction>>Status>>"
					+ sessionFactory.getCurrentSession().getTransaction().isActive());
		SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(sql).addEntity(clazz);
		int index = 0;
		if (vals != null && vals.length > 0)
			for (Object val : vals)
				query.setParameter(index++, val);
		return query.list();
	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public <T> List<T> query(Class<T> clazz, String sql, Object[] vals, String[] columns, Type[] types)
			throws Exception {
		if (log.isDebugEnabled())
			log.debug("[BaseDao]>query>>Transaction>>Status>>"
					+ sessionFactory.getCurrentSession().getTransaction().isActive());
		SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(sql);

		int index = 0;
		if (vals != null && vals.length > 0)
			for (Object val : vals)
				query.setParameter(index++, val);

		if (columns != null && columns.length > 0) {
			for (int i = 0; i < columns.length; i++) {
				query.addScalar(columns[i], types[i]);
			}
		}

		return query.setResultTransformer(Transformers.aliasToBean(clazz)).list();
	}

	public int getMaxCount(String sql, Object... vals) {
		sql = "SELECT COUNT(1) AS count FROM ( " + sql + " ) AS TBL ";
		if (log.isDebugEnabled())
			log.debug("[BaseDao]>getMaxCount>>" + sql);
		SQLQuery query = sessionFactory.getCurrentSession().createSQLQuery(sql).addScalar("count", Hibernate.INTEGER);
		int index = 0;

		if (vals != null && vals.length > 0)
			for (Object val : vals)
				query.setParameter(index++, val);

		return (Integer) query.list().get(0);
	}

}
